package com.ak.game.netty;

import com.ak.game.exception.ServiceException;
import com.ak.game.service.PnGameService;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;

/**
 * websocket长连接权限验证的handler代理类
 */
@Slf4j
public class WebSocketAuthHandler extends ChannelInboundHandlerAdapter {

    private final PnGameService gameService;

    public WebSocketAuthHandler(PnGameService gameService) {
        this.gameService = gameService;
    }

    /**
     * 处理请求
     *
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //获取sign数据
        Map<String, String> map = extractTokenFromMessage(msg);
        //实现此方法以验证sign的有效性
        if (!isValidToken(map)) {
            //处理无效sign的情况，例如关闭连接或返回错误信息
            ctx.close();
        } else {
            // 验证成功则移除此验证handler代理类
            super.channelRead(ctx, msg);
            ctx.pipeline().remove(WebSocketAuthHandler.class);
        }
    }

    /**
     * 拿取sign参数
     *
     * @param msg
     * @return
     */
    private Map<String, String> extractTokenFromMessage(Object msg) {
        if (msg instanceof FullHttpRequest) {
            FullHttpRequest request = (FullHttpRequest) msg;
            HttpHeaders headers = request.headers();
            log.info("收到连接请求，headers参数={}",headers);
            log.info("sign={}",headers.get("sign"));
            log.info("game_id={}",headers.get("game_id"));
            log.info("timestamp={}",headers.get("timestamp"));
            if (StringUtil.isNullOrEmpty(headers.get("sign")) || StringUtil.isNullOrEmpty(headers.get("game_id")) || StringUtil.isNullOrEmpty(headers.get("timestamp"))) {
                throw new ServiceException("参数不全");
            }
            return Map.of("sign", headers.get("sign"),"game_id", headers.get("game_id"),"timestamp", headers.get("timestamp"));
        } else {
            throw new ServiceException("请求类型不正确");
        }
    }

    /**
     * 验证签名
     *
     * @param map
     * @return
     */
    private boolean isValidToken(Map<String, String> map) {
        // sign、gameId、timestamp为null或者''直接拒绝连接
        if (StringUtil.isNullOrEmpty(map.get("sign")) || StringUtil.isNullOrEmpty(map.get("game_id")) || StringUtil.isNullOrEmpty(map.get("timestamp")) ) {
            return false;
        }
        //验签
        return gameService.validSignature(map.get("sign"),map.get("game_id"),Long.parseLong(map.get("timestamp")));
    }

    /**
     * 管道异常处理，防止资源泄露
     * @param ctx
     * @param cause
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error("连接失败：{}", cause.getMessage()); // 记录日志
        ctx.close(); // 关闭发生异常的通道，防止资源泄露
    }
}
